package com.lzh.runke.core.web_base.view.excel;

import com.lzh.runke.core.web_base.autoconfigure.WebAutoConfigProperties;
import com.lzh.runke.core.web_base.constant.DateConstant;
import com.lzh.runke.core.web_base.enums.BaseEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.RegionUtil;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.servlet.view.document.AbstractXlsxView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.ParameterizedType;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

@Slf4j
public abstract class AbstractExcelView<T> extends AbstractXlsxView {

    @Resource
    private WebAutoConfigProperties webAutoConfigProperties;

    @Resource
    private ResourceLoader resourceLoader;

    protected String templateName;

    protected static final String XLS = ".xls";

    protected static final String XLSX = ".xlsx";

    public AbstractExcelView() {
        super();

        ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
        // 获取第一个类型参数的真实类型
        Class<T> clazz = (Class<T>) pt.getActualTypeArguments()[0];
        this.templateName = ClassUtils.getShortClassName(clazz) + XLSX;
    }

    @Override
    protected Workbook createWorkbook(Map<String, Object> model, HttpServletRequest request) {
        try {
            // poi 4.1.0 WorkbookFactory.create() 入参为File时会修改原始文件，应传入FileInputStream
            return WorkbookFactory.create(resourceLoader.getResource(webAutoConfigProperties.getExcelTemplatePath() + templateName).getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    // 生成下边框样式（居左，上下居中）
    protected CellStyle buildStyleBottom(Workbook workbook) {
        return buildStyleBottom(workbook, null, null);
    }

    // 生成下边框样式（自定义对齐方式）
    protected CellStyle buildStyleBottom(Workbook workbook, HorizontalAlignment hAlign, VerticalAlignment vAlign) {
        CellStyle style = workbook.createCellStyle();

        // 设置对齐样式
        hAlign = null == hAlign ? HorizontalAlignment.LEFT : hAlign;
        vAlign = null == vAlign ? VerticalAlignment.CENTER : vAlign;
        style.setAlignment(hAlign);
        style.setVerticalAlignment(vAlign);

        // 设置边框
        style.setBorderBottom(BorderStyle.THIN);

        return style;
    }

    // 生成全边框样式（居左，上下居中）
    protected CellStyle buildStyleAll(Workbook workbook) {
        return buildStyleAll(workbook, null, null);
    }

    // 生成全边框样式（自定义对齐方式）
    protected CellStyle buildStyleAll(Workbook workbook, HorizontalAlignment hAlign, VerticalAlignment vAlign) {
        CellStyle style = workbook.createCellStyle();

        // 设置对齐样式
        hAlign = null == hAlign ? HorizontalAlignment.LEFT : hAlign;
        vAlign = null == vAlign ? VerticalAlignment.CENTER : vAlign;
        style.setAlignment(hAlign);
        style.setVerticalAlignment(vAlign);

        // 设置边框
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);

        return style;
    }

    // 生成无边框样式（居左，上下居中）
    protected CellStyle buildStyleNone(Workbook workbook) {
        return buildStyleNone(workbook, null, null);
    }

    // 生成无边框样式（自定义对齐方式）
    protected CellStyle buildStyleNone(Workbook workbook, HorizontalAlignment hAlign, VerticalAlignment vAlign) {
        CellStyle style = workbook.createCellStyle();

        // 设置对齐样式
        hAlign = null == hAlign ? HorizontalAlignment.LEFT : hAlign;
        vAlign = null == vAlign ? VerticalAlignment.CENTER : vAlign;
        style.setAlignment(hAlign);
        style.setVerticalAlignment(vAlign);

        return style;
    }

    // 设置单元格内容 字符串
    protected void setCellValue(Row row, int columnNum, String value) {
        Cell cell = row.getCell(columnNum);
        cell.setCellValue(StringUtils.isBlank(value) ? "" : value);
    }

    // 设置单元格内容 数值
    protected void setCellValue(Row row, int columnNum, double value) {
        setCellValue(row, columnNum, String.valueOf(value));
    }

    protected void setCellValue(Row row, int columnNum, Double value) {
        setCellValue(row, columnNum, null == value ? "" : value.toString());
    }

    protected void setCellValue(Row row, int columnNum, Float value) {
        setCellValue(row, columnNum, null == value ? "" : value.toString());
    }

    protected void setCellValue(Row row, int columnNum, Long value) {
        setCellValue(row, columnNum, null == value ? "" : value.toString());
    }

    protected void setCellValue(Row row, int columnNum, Integer value) {
        setCellValue(row, columnNum, null == value ? "" : value.toString());
    }

    protected void setCellValue(Row row, int columnNum, Short value) {
        setCellValue(row, columnNum, null == value ? "" : value.toString());
    }

    protected void setCellValue(Row row, int columnNum, Byte value) {
        setCellValue(row, columnNum, null == value ? "" : value.toString());
    }

    // 设置单元格内容 日期（默认格式：FMT_YMDHMS）
    protected void setCellValue(Row row, int columnNum, Date value) {
        setCellValue(row, columnNum, value, null);
    }

    // 设置单元格内容 日期（自定义格式）
    protected void setCellValue(Row row, int columnNum, Date value, String format) {
        SimpleDateFormat fmt = new SimpleDateFormat(StringUtils.isBlank(format) ? DateConstant.FMT_YMDHMS : format);
        setCellValue(row, columnNum, null == value ? "" : fmt.format(value));
    }

    // 设置单元格内容 枚举基类
    protected void setCellValue(Row row, int columnNum, BaseEnum value) {
        setCellValue(row, columnNum, null == value ? "" : value.getName());
    }

    // 新增单元格并添加样式，赋值 字符串
    protected void addCell(Row row, int column, String value, CellStyle style) {
        Cell cell = row.createCell(column);
        cell.setCellStyle(style);
        cell.setCellValue(StringUtils.isBlank(value) ? "" : value);
    }

    // 新增单元格并添加样式，赋值 数值
    protected void addCell(Row row, int column, double value, CellStyle style) {
        addCell(row, column, String.valueOf(value), style);
    }

    protected void addCell(Row row, int column, Double value, CellStyle style) {
        addCell(row, column, null == value ? "" : value.toString(), style);
    }

    protected void addCell(Row row, int column, Float value, CellStyle style) {
        addCell(row, column, null == value ? "" : value.toString(), style);
    }

    protected void addCell(Row row, int column, Long value, CellStyle style) {
        addCell(row, column, null == value ? "" : value.toString(), style);
    }

    protected void addCell(Row row, int column, Integer value, CellStyle style) {
        addCell(row, column, null == value ? "" : value.toString(), style);
    }

    protected void addCell(Row row, int column, Short value, CellStyle style) {
        addCell(row, column, null == value ? "" : value.toString(), style);
    }

    protected void addCell(Row row, int column, Byte value, CellStyle style) {
        addCell(row, column, null == value ? "" : value.toString(), style);
    }

    // 新增单元格并添加样式，赋值 日期（默认格式：FMT_YMDHMS）
    protected void addCell(Row row, int column, Date value, CellStyle style) {
        addCell(row, column, value, null, style);
    }

    // 新增单元格并添加样式，赋值 日期（自定义格式）
    protected void addCell(Row row, int column, Date value, String format, CellStyle style) {
        SimpleDateFormat fmt = new SimpleDateFormat(StringUtils.isBlank(format) ? DateConstant.FMT_YMDHMS : format);
        addCell(row, column, null == value ? "" : fmt.format(value), style);
    }

    // 新增单元格并添加样式，赋值 枚举基类
    protected void addCell(Row row, int column, BaseEnum value, CellStyle style) {
        addCell(row, column, null == value ? "" : value.getName(), style);
    }

    // 合并单元格
    protected int merge(Sheet sheet, int firstRow, int lastRow, int firstColumn, int lastColumn) {
        return merge(sheet, firstRow, lastRow, firstColumn, lastColumn, null);
    }

    // 合并单元格并添加样式
    protected int merge(Sheet sheet, int firstRow, int lastRow, int firstColumn, int lastColumn, CellStyle style) {
        CellRangeAddress cra = new CellRangeAddress(firstRow, lastRow, firstColumn, lastColumn);
        if (null != style) {
            RegionUtil.setBorderBottom(style.getBorderBottom(), cra, sheet);
            RegionUtil.setBottomBorderColor(style.getBottomBorderColor(), cra, sheet);

            RegionUtil.setBorderLeft(style.getBorderLeft(), cra, sheet);
            RegionUtil.setLeftBorderColor(style.getLeftBorderColor(), cra, sheet);

            RegionUtil.setBorderRight(style.getBorderRight(), cra, sheet);
            RegionUtil.setRightBorderColor(style.getRightBorderColor(), cra, sheet);

            RegionUtil.setBorderTop(style.getBorderTop(), cra, sheet);
            RegionUtil.setTopBorderColor(style.getTopBorderColor(), cra, sheet);
        }

        return sheet.addMergedRegion(cra);
    }

    protected void setExportFilename(HttpServletResponse response, String filename) {
        try {
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name()));
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}
